{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import keras\n",
    "from keras import layers\n",
    "from keras import models\n",
    "import os\n",
    "os.environ[\"CUDA_VISIBLE_DEVICES\"]=\"0\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 训练epochs数量\n",
    "EPOCHS = 20\n",
    "# 训练批大小\n",
    "BATCH_SIZE = 5\n",
    "# 输入的连续时间序列长度\n",
    "MAX_STEPS = 30\n",
    "# 前区号码种类数\n",
    "FRONT_VOCAB_SIZE = 10\n",
    "# 后区号码种类数\n",
    "# BACK_VOCAB_SIZE = 11\n",
    "# dropout随机失活比例\n",
    "DROPOUT_RATE = 0.5\n",
    "# 长短期记忆网络单元数\n",
    "LSTM_UNITS = 64\n",
    "# 前区需要选择的号码数量\n",
    "FRONT_SIZE = 5\n",
    "# 后区需要选择的号码数量\n",
    "# BACK_SIZE = 2\n",
    "# 保存训练好的参数的路径\n",
    "CHECKPOINTS_PATH = 'checkpoints2'\n",
    "# 预测下期号码时使用的训练好的模型参数的路径，默认使用完整数据集训练出的模型\n",
    "PREDICT_MODEL_PATH = '{}/model_checkpoint_x'.format(CHECKPOINTS_PATH)\n",
    "# 预测的时候，预测几注彩票,默认5注\n",
    "PREDICT_NUM = 5\n",
    "# 数据集路径\n",
    "DATASET_PATH = 'lotto.csv'\n",
    "# 数据集下载地址\n",
    "# LOTTO_DOWNLOAD_URL = 'https://www.js-lottery.com/PlayZone/downLottoData.html'\n",
    "LOTTO_DOWNLOAD_URL = 'http://106.13.233.100:3002/getLimitData/3000'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "load_data = []\n",
    "def getData():\n",
    "  try:\n",
    "    resp = requests.get(LOTTO_DOWNLOAD_URL)\n",
    "    if resp.status_code == 200:\n",
    "        respJson = resp.json()\n",
    "        respJson.reverse()\n",
    "        for i in range(len(respJson)):\n",
    "          d = respJson[i]\n",
    "          # load_data.append([d[\"issueNo\"],d[\"one\"],d[\"two\"],d[\"three\"],d[\"four\"],d[\"five\"]])\n",
    "          # load_data.append([d[\"one\"],d[\"two\"],d[\"three\"],d[\"four\"],d[\"five\"]])\n",
    "          load_data.append(d[\"five\"])\n",
    "        print(len(load_data))\n",
    "        print(load_data)\n",
    "        # print(load_data[:10])\n",
    "        return load_data\n",
    "    else:\n",
    "      raise Exception('获取数据失败！')\n",
    "  except Exception as e:\n",
    "    print(e)\n",
    "\n",
    "getData()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def split_data():\n",
    "  x=[]\n",
    "  y=[]\n",
    "  total = len(load_data)\n",
    "\n",
    "  if MAX_STEPS >= total: print(\"错误\")\n",
    "  for item in range(MAX_STEPS, total, 1):\n",
    "    x.append(load_data[item - MAX_STEPS:item])\n",
    "    y.append(load_data[item])\n",
    "  # print(y)\n",
    "  # print(x)\n",
    "\n",
    "  np_x = np.zeros((total-MAX_STEPS, MAX_STEPS, FRONT_VOCAB_SIZE))\n",
    "  np_y = np.zeros((total-MAX_STEPS, FRONT_VOCAB_SIZE))\n",
    "\n",
    "  for i in range(0, len(x), 1):\n",
    "    # print(i)\n",
    "    yy = y[i]\n",
    "    np_y[i][yy] = 1\n",
    "    for j in range(0, len(x[i]), 1):\n",
    "      xx = x[i][j]\n",
    "      np_x[i][j][xx] = 1\n",
    "      # print(j)\n",
    "\n",
    "  print(np_x)\n",
    "  print(np_y)\n",
    "\n",
    "  train_data_rate = 0.9\n",
    "  train_data_rate_num = int(train_data_rate * len(x))\n",
    "  train_x = np_x[:train_data_rate_num]\n",
    "  train_y = np_y[:train_data_rate_num]\n",
    "  test_x = np_x[train_data_rate_num:]\n",
    "  test_y = np_y[train_data_rate_num:]\n",
    "  # print(9)\n",
    "  return train_x, train_y, test_x, test_y, \n",
    "\n",
    "train_x, train_y, test_x, test_y = split_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def myModel():\n",
    "  # 这是一个多输入模型，inputs用来保存所有的输入层\n",
    "  inputs = []\n",
    "  # 这是一个多输出模型，outputs用来保存所有的输出层\n",
    "  outputs = []\n",
    "\n",
    "  # 输入层\n",
    "  x_input = layers.Input((MAX_STEPS, FRONT_VOCAB_SIZE))\n",
    "  # 双向循环神经网络\n",
    "  x = layers.Bidirectional(layers.LSTM(LSTM_UNITS, return_sequences=True))(x_input)\n",
    "  # 随机失活\n",
    "  x = layers.Dropout(rate=DROPOUT_RATE)(x)\n",
    "  # x = layers.Bidirectional(layers.LSTM(LSTM_UNITS, return_sequences=True))(x)\n",
    "  x = layers.TimeDistributed(layers.Dense(FRONT_VOCAB_SIZE * 3))(x)\n",
    "  x = layers.Dropout(rate=DROPOUT_RATE)(x)\n",
    "  # 平铺\n",
    "  x = layers.Flatten()(x)\n",
    "  # 全连接\n",
    "  x = layers.Dense(FRONT_VOCAB_SIZE, activation='relu')(x)\n",
    "  # 保存输入层\n",
    "  inputs.append(x_input)\n",
    "  # x = layers.Dense(FRONT_VOCAB_SIZE, activation='relu')(x)\n",
    "  outputs.append(x)\n",
    "\n",
    "  # 创建模型\n",
    "  model = models.Model(inputs, outputs)\n",
    "  # 指定优化器和损失函数\n",
    "  model.compile(optimizer=keras.optimizers.Adam(), metrics = ['accuracy'],\n",
    "    loss=[keras.losses.categorical_crossentropy for __ in range(FRONT_SIZE)],\n",
    "    loss_weights=[1, 1, 1, 1, 1])\n",
    "  # 查看网络结构\n",
    "  model.summary()\n",
    "\n",
    "  return model\n",
    "\n",
    "model = myModel()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建保存权重的文件夹\n",
    "if not os.path.exists(CHECKPOINTS_PATH):\n",
    "  os.mkdir(CHECKPOINTS_PATH)\n",
    "\n",
    "# 开始训练\n",
    "epoch = 25\n",
    "H = model.fit(train_x, train_y, validation_data=(test_x, test_y), batch_size=BATCH_SIZE, epochs=epoch)\n",
    "# 保存当前权重\n",
    "model.save_weights('{}/model_checkpoint_{}'.format(CHECKPOINTS_PATH, epoch))\n",
    "# print('已训练完第{}轮，尝试模拟购买彩票...'.format(epoch))\n",
    "# results.append(simulate(lotto_dataset.test_np_x, lotto_dataset.test_np_y))\n",
    "\n",
    "x = np.arange(0, epoch)\n",
    "plt.plot(x, H.history[\"loss\"], label=\"loss\")\n",
    "plt.plot(x, H.history[\"val_loss\"], label=\"val_loss\")\n",
    "plt.plot(x, H.history[\"accuracy\"], label=\"accuracy\")\n",
    "plt.plot(x, H.history[\"val_accuracy\"], label=\"val_accuracy\")\n",
    "plt.title('epoch:{}, BATCH_SIZE:{}, MAX_STEPS:{}, DROPOUT_RATE:{}, LSTM_UNITS:{},'.format(epoch,BATCH_SIZE,MAX_STEPS,DROPOUT_RATE,LSTM_UNITS))\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.9.13 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "239cd0f6924d34dc9a29cd51ff042db2679e9319f05891fd61214d5969f7bbf8"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
